package cn.b.sky.common.utils;

import org.apache.commons.lang3.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

public class DateUtils extends SimpleDateFormat {
  /**
  * 注释内容
  */
  private static final long serialVersionUID = -2987750868895651661L;

  /**
     * 时间格式为yyyy-MM-dd HH:mm:ss
     */
  public static final String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";

  /**
   * 时间格式为yyyy-MM-dd HH:mm:ss.sss
   */
  public static final String YYYY_MM_DD_HH_MM_SS_S = "yyyy-MM-dd HH:mm:ss.SSS";

  /**
   * 时间格式为yyyy-MM-dd
   */
  public static final String YYYY_MM_DD = "yyyy-MM-dd";

  /**
   * 时间格式为yyyyMMddHHmmss
   */
  public static final String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
  
  /**
   * 时间格式为yyyyMMdd_HHmmss_sss
   */
  public static final String YYYYMMDD_HHMMSS_SSS = "yyyyMMdd_HHmmss_sss";

  /**
   * 时间格式为ddHHmmss
   */
  public static final String DDHHMMSS = "ddHHmmss";

  /**
   * 时间格式为HHmmss
   */
  public static final String HHMMSS = "HHmmss";

  /**
   * 时间格式为yyyy-MM-dd HH:mm
   */
  public static final String YYYY_MM_DD_HH_MM = "yyyy-MM-dd HH:mm";

  /**
   * 时间格式为yyyy-MM-dd HH
   */
  public static final String YYYY_MM_DD_HH = "yyyy-MM-dd HH";

  /**
   * DATETOOL
   */
  private static DateUtils dateUtils = null;

  public static final int MILLIS = 1000;
  
  public static final int SECOND = 60;

  public static final int MINUTE = 60;

  public static final int HOUR = 24;

  public static final int DAY = 30;
  /**
   * <默认私有构造函数>
   */
  private DateUtils() {
    super(YYYY_MM_DD_HH_MM_SS);
  }

  /** 
   * <默认构造函数>
   * @param pattern 模态
   */
  private DateUtils(String pattern) {
    super(pattern);
  }

  /**
   * 此类构造的日期工具类不可以格式化日期
   * @return DateTools
   */
  public static DateUtils getDateUtils() {
    if (null == dateUtils) {
      dateUtils = new DateUtils();
    }
    return dateUtils;
  }

  /**
   * 此类构造的日期工具类可以格式化日期
   * @param mode mode模式 以哪种时间模式去创建或转换
   * @return DateTools
   */
  public static DateUtils getDateUtils(String mode) {
    return new DateUtils(mode);
  }

  /**
   * 得到会传入日期的月份
   * @param date 日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getMonth(Date date) throws ParseException {
    setCalendar(date);
    return calendar.get(Calendar.MONTH) + 1;
  }

  /**
   * 得到会传入日期的年份
   * @param date 日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getYear(Date date) throws ParseException {
    setCalendar(date);
    return calendar.get(Calendar.YEAR);
  }

  /**
   * 得到会传入日期的是日期所在月的哪一天
   * @param date 日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getDate(Date date) throws ParseException {
    setCalendar(date);
    return calendar.get(Calendar.DATE) + 1;
  }

  /**
   * 得到会传入日期的分钟
   * @param date 日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getMinute(Date date) throws ParseException {
    setCalendar(date);
    return calendar.get(Calendar.MINUTE);
  }

  /**
   * 得到会传入日期的小时
   * @param date 日期
   * @param isStandard 是否是24小时制的,true:是
   * @return int
   * @throws ParseException ParseException
   */
  public int getHour(Date date, boolean isStandard) throws ParseException {
    setCalendar(date);
    if (isStandard) {
      return calendar.get(Calendar.HOUR_OF_DAY);
    } else {
      return calendar.get(Calendar.HOUR);
    }
  }

  /**
   * 得到会传入日期的小时
   * @param date 日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getSecond(Date date) throws ParseException {
    setCalendar(date);
    return calendar.get(Calendar.SECOND);
  }

  /**
   * 得到会传入日期的月份
   * @param strDate 字符串日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getMonth(String strDate) throws ParseException {
    setCalendar(strDate);
    return calendar.get(Calendar.MONTH) + 1;
  }

  /**
   * 得到会传入日期的年份
   * @param strDate 字符串日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getYear(String strDate) throws ParseException {
    setCalendar(strDate);
    return calendar.get(Calendar.YEAR);
  }

  /**
   * 得到会传入日期的是日期所在月的哪一天
   * @param strDate 字符串日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getDate(String strDate) throws ParseException {
    setCalendar(strDate);
    return calendar.get(Calendar.DATE) + 1;
  }

  /**
   * 得到会传入日期的分钟
   * @param strDate 字符串日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getMinute(String strDate) throws ParseException {
    setCalendar(strDate);
    return calendar.get(Calendar.MINUTE);
  }

  /**
   * 得到会传入日期的小时
   * @param strDate 字符串日期
   * @param isStandard 是否是24小时制的,true:是
   * @return int
   * @throws ParseException ParseException
   */
  public int getHour(String strDate, boolean isStandard) throws ParseException {
    setCalendar(strDate);
    if (isStandard) {
      return calendar.get(Calendar.HOUR_OF_DAY);
    } else {
      return calendar.get(Calendar.HOUR);
    }
  }

  /**
   * 得到会传入日期的小时
   * @param strDate 字符串日期
   * @return int
   * @throws ParseException ParseException
   */
  public int getSecond(String strDate) throws ParseException {
    setCalendar(strDate);
    return calendar.get(Calendar.SECOND);
  }

  /**
   * 在原有的时间小时上加上或减去多少
   * @param date 原有时间
   * @param levevHour 要加减的小时数
   * @param isStandard 是还是24小时制
   * @return Date
   */
  public Date operationHour(Date date, int levevHour, boolean isStandard) {
    setCalendar(date);
    if (isStandard) {
      calendar.add(Calendar.HOUR_OF_DAY, levevHour);
    } else {
      calendar.add(Calendar.HOUR, levevHour);
    }
    return calendar.getTime();
  }

  /**
   * 在原有的时间分钟上加上或减去多少
   * @param date 原有时间
   * @param levevMinute 要加减的分钟数
   * @return Date
   */
  public Date operationMinute(Date date, int levevMinute) {
    setCalendar(date);
    calendar.add(Calendar.MINUTE, levevMinute);
    return calendar.getTime();
  }

  /**
   * 在原有的时间年份上加上或减去多少
   * @param date 原有时间
   * @param levevYear 要加减的年份数
   * @return Date
   */
  public Date operationYear(Date date, int levevYear) {
    setCalendar(date);
    calendar.add(Calendar.YEAR, levevYear);
    return calendar.getTime();
  }

  /**
   * 在原有的时间月份上加上或减去多少
   * @param date 原有时间
   * @param levevMonth 要加减的月份数
   * @return Date
   */
  public Date operationMonth(Date date, int levevMonth) {
    setCalendar(date);
    calendar.add(Calendar.MONTH, levevMonth);
    return calendar.getTime();
  }

  /**
   * 在原有的时间天数上加上或减去多少
   * @param date 原有时间
   * @param days 要加减的天数 负的为减
   * @return Date
   */
  public Date operationDay(Date date, int days) {
    setCalendar(date);
    calendar.add(Calendar.DATE, days);     
    return calendar.getTime();
  }

  /**
   * 在原有的时间秒上加上或减去多少
   * @param date 原有时间
   * @param levevSecond 要加减的秒数
   * @return Date
   */
  public Date operationSecond(Date date, int levevSecond) {
    setCalendar(date);
    calendar.add(Calendar.SECOND, levevSecond);
    return calendar.getTime();
  }

  /**
   * 在原有的时间小时上加上或减去多少(字符串时间)
   * @param strDate 原有时间
   * @param levevHour 要加减的小时数
   * @param isStandard 是还是24小时制
   * @return String
   * @throws ParseException ParseException
   */
  public String operationHour(String strDate, int levevHour, boolean isStandard) throws ParseException {
    setCalendar(strDate);
    if (isStandard) {
      calendar.add(Calendar.HOUR_OF_DAY, levevHour);
    } else {
      calendar.add(Calendar.HOUR, levevHour);
    }
    return format(calendar.getTime());
  }

  /**
   * 在原有的时间分钟上加上或减去多少
   * @param strDate 原有时间
   * @param levevMinute 要加减的分钟数
   * @return String
   * @throws ParseException ParseException
   */
  public String operationMinute(String strDate, int levevMinute) throws ParseException {
    setCalendar(strDate);
    calendar.add(Calendar.MINUTE, levevMinute);
    return format(calendar.getTime());
  }

  /**
   * 在原有的时间年份上加上或减去多少
   * @param strDate 原有时间
   * @param levevYear 要加减的年份数
   * @return String
   * @throws ParseException ParseException
   */
  public String operationYear(String strDate, int levevYear) throws ParseException {
    setCalendar(strDate);
    calendar.add(Calendar.YEAR, levevYear);
    return format(calendar.getTime());
  }

  /**
   * 在原有的时间月份上加上或减去多少
   * @param strDate 原有时间
   * @param levevMonth 要加减的月份数
   * @return Date
   * @throws ParseException ParseException
   */
  public String operationMonth(String strDate, int levevMonth) throws ParseException {
    setCalendar(strDate);
    calendar.add(Calendar.MONTH, levevMonth);
    return format(calendar.getTime());
  }

  /**
   * 在原有的时间月份上加上或减去多少
   * @param strDate 原有时间
   * @param days 要加减的天数
   * @return Date
   * @throws ParseException ParseException
   */
  public String operationDay(String strDate, int days) throws ParseException {
    setCalendar(strDate);
    calendar.add(Calendar.DATE, days);
    return format(calendar.getTime());
  }

  /**
   * 在原有的时间秒上加上或减去多少
   * @param strDate 原有时间
   * @param levevSecond 要加减的秒数
   * @return Date
   * @throws ParseException ParseException
   */
  public String operationSecond(String strDate, int levevSecond) throws ParseException {
    setCalendar(strDate);
    calendar.add(Calendar.SECOND, levevSecond);
    return format(calendar.getTime());
  }

  /**
   * 返回两个时间段之间的间隔(天)
   * @param maxDate 时间点1
   * @param minDate 时间点2
   * @return int
   * @throws ParseException ParseException
   */
  public int getDaysOperationDate(Date maxDate, Date minDate) throws ParseException {
    return (int) StrictMath.abs((maxDate.getTime() - minDate.getTime()) / (HOUR*SECOND*MINUTE*MILLIS));
  }

  /**
   * 
   * <strong>Title : getDaysOperationDate<br></strong>
   * <strong>Description : </strong>返回两个时间段之间的间隔(天)<br> 
   * <strong>Create on : 2016-3-31 下午5:17:36<br></strong>
   * <p>
   * @param maxDate
   * @param minDate
   * @return
   * @throws ParseException
   * int
   * @throws 
   * @author lidapeng<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public int getDaysOperationDate(String maxDate, String minDate) throws ParseException {
    return (int) StrictMath.abs((parse(maxDate).getTime() - parse(minDate).getTime()) / (HOUR*SECOND*MINUTE*MILLIS));
  }

  /**
   * 
   * <strong>Title : getHoursOperationDate<br></strong>
   * <strong>Description : </strong>获取时间的小时数<br> 
   * <strong>Create on : 2016-3-31 下午5:26:02<br></strong>
   * <p>
   * @param beginDate
   * @param endDate
   * @return
   * int
   * @throws 
   * @author lidapeng<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public int getHoursOperationDate(Date beginDate, Date endDate) {
    if (beginDate == null) {
      return (int) endDate.getTime() / (SECOND*MINUTE*MILLIS);
    }
    if (endDate == null) {
      return 0;
    }
    return (int) (endDate.getTime() - beginDate.getTime()) / (SECOND*MINUTE*MILLIS);
  }

  /**
   * 判断用户输入的时间是否介于两个时间段内
   * @param afterDate 结束时间
   * @param beforeDate 起始时间
   * @param currentDate 用户输入的时间
   * @return boolean true:是介于两个时间段之间
   */
  public boolean compareDate(Date afterDate, Date beforeDate, Date currentDate) {
    if (currentDate.after(beforeDate) && currentDate.before(afterDate)) {
      return true;
    }
    return false;
  }

  /**
   * 判断用户输入的时间是否介于两个时间段内(字符串时间)
   * @param strAfterDate 结束时间
   * @param strBeforeDate 起始时间
   * @param strCurrentDate 用户输入的时间
   * @return boolean true:是介于两个时间段之间
   * @throws ParseException ParseException
   */
  public boolean compareDate(String strAfterDate, String strBeforeDate, String strCurrentDate) throws ParseException {
    Date currentDate = parse(strCurrentDate);
    if (currentDate.after(parse(strBeforeDate)) && currentDate.before(parse(strAfterDate))) {
      return true;
    }
    return false;
  }

  /**
   * 返回系统的当前时间,以字符串形式
   * @return String
   */
  public String getSystemStrDate() {
    return format(new Date());
  }

  /**
   * 设置日历的时间
   */
  private void setCalendar(Date date) {
    calendar.setTime(date);
  }

  /**
   * 设置日历的时间
   */
  private void setCalendar(String strDate) throws ParseException {
    calendar.setTime(parse(strDate));
  }

  /**
   * 判断当前时间是否介于开始时间和结束时间
   * @param startTime 开始时间
   * @param endTime 结束时间
   * @return boolean
   * @throws ParseException ParseException
   */
  public boolean compareDate(String startTime, String endTime) throws ParseException {
    Date currentDate = new Date();
    String strCurrentTime = format(currentDate);
    String time = strCurrentTime.substring(0, strCurrentTime.indexOf(" ") + 1);
    Date startDate = parse(time + startTime);
    Date endDate = parse(time + endTime);
    if (currentDate.before(startDate)) {
      if (currentDate.before(endDate)) {
        return true;
      }
    } else if (endDate.before(startDate)) {
      if (currentDate.after(startDate)) {
        return true;
      }
    } else {
      if (currentDate.after(startDate) && currentDate.before(endDate)) {
        return true;
      }
    }
    return false;
  }

  /**
   * 取得日期的最早时间00:00:00
   * @param date
   * @return
   * @throws ParseException
   */
  public Date getDateEarliestTime(Date date) throws ParseException {
    String dateStr = DateUtils.getDateUtils(YYYY_MM_DD).format(date).concat(" 00:00:00");
    return DateUtils.getDateUtils(YYYY_MM_DD_HH_MM_SS).parse(dateStr);
  }

  /**
   * 取得日期的晚时间23:59:59
   * @param date
   * @return
   * @throws ParseException
   */
  public Date getDateLatestTime(Date date) throws ParseException {
    String dateStr = DateUtils.getDateUtils(YYYY_MM_DD).format(date).concat(" 23:59:59");
    return DateUtils.getDateUtils(YYYY_MM_DD_HH_MM_SS).parse(dateStr);
  }

  public Date getCurrentDate() {
    return new Date();
  }

  /**
   * 
   * <strong>Title : getDateStr<br></strong>
   * <strong>Description : </strong>格式化字符串<br> 
   * <strong>Create on : 2016-3-29 下午4:08:53<br></strong>
   * <p>
   * @param date
   * @return
   * String
   * @throws 
   * @author lidapeng<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public String getDateStr(Date date) {
    if (date == null) {
      return null;
    }
    return format(date);
  }

  /**
   * 
   * <strong>Title : getHSMStrByTwoDate<br>
   * </strong> <strong>Description : </strong>获取两个日期之差的时分秒<br>
   * <strong>Create on : 2014-8-27 下午08:16:40<br>
   * </strong>
   * <p>
   * 
   * @param mindate
   * @param maxdate
   * @return String
   * @throws
   * @author dapeng_li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   *          <strong>修改历史:</strong><br>
   *          修改人 | 修改日期 | 修改描述<br>
   *          -------------------------------------------<br>
   * <br>
   * <br>
   */
  public String getHSMStrByTwoDate(Date mindate, Date maxdate) {
    if (mindate == null || maxdate == null) {
      return null;
    }
    long t1 = maxdate.getTime();
    long t2 = mindate.getTime();

    return getHSMStrByLongTime(t1 - t2);
  }

  public String getHSMStrByLongTime(Long time) {
    if (time == null) {
      return null;
    }
    int hours = (int) (time / (SECOND*MINUTE*MILLIS));
    int minutes = (int) ((time / MILLIS - hours * SECOND * MINUTE) / SECOND);
    int second = (int) (time / MILLIS - hours * SECOND * MINUTE - minutes * MINUTE);
    return hours + ":" + minutes + ":" + second;
  }

  /**
   * 
   * <strong>Title : getDateFromStr<br>
   * </strong> <strong>Description : </strong>字符串转日期<br>
   * <strong>Create on : 2014-8-19 上午09:53:30<br>
   * </strong>
   * <p>
   * 
   * @param datestr
   * @return
   * @throws ParseException
   *             Date
   * @throws
   * @author dapeng_li<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   *          <strong>修改历史:</strong><br>
   *          修改人 | 修改日期 | 修改描述<br>
   *          -------------------------------------------<br>
   * <br>
   * <br>
   */
  public Date getDateFromStr(String datestr) throws ParseException {
    if (StringUtils.isBlank(datestr)) {
      return null;
    }
    return parse(datestr);
  }

  /**
   * 
   * <strong>Title : getDatesBetweenTwoDate<br></strong>
   * <strong>Description : </strong>列出开始结束日期内的每天<br> 
   * <strong>Create on : 2016-4-1 下午3:08:19<br></strong>
   * <p>
   * @param begin 开始日期
   * @param end   结束日期
   * @return
   * @throws ParseException
   * List<String>
   * @throws 
   * @author ZiQiang.Zhao<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public List<String> getDatesBetweenTwoDate(String begin, String end) throws ParseException {
    
    if (StringUtils.isBlank(begin) || StringUtils.isBlank(end)) {
      throw new IllegalArgumentException("The date must not be null");
    }
    
    SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD);

    return getDatesBetweenTwoDate(sdf.parse(begin), sdf.parse(end));
  }

  /**
   * 
   * <strong>Title : getDatesBetweenTwoDate<br></strong>
   * <strong>Description : </strong>列出开始结束日期内的每天<br> 
   * <strong>Create on : 2016-4-1 下午3:18:39<br></strong>
   * <p>
   * @param beginDate 开始日期
   * @param endDate   结束日期
   * @return
   * @throws ParseException
   * List<String>
   * @throws 
   * @author ZiQiang.Zhao<br>
   * @version <strong>v1.0.0</strong><br>
   * <br>
   * <strong>修改历史:</strong><br>
   * 修改人 | 修改日期 | 修改描述<br>
   * -------------------------------------------<br>
   * <br>
   * <br>
   */
  public  List<String> getDatesBetweenTwoDate(Date beginDate, Date endDate) throws ParseException {
    
    if ((beginDate == null) || (endDate == null)) {
      throw new IllegalArgumentException("The date must not be null");
    }
    
    SimpleDateFormat sdf = new SimpleDateFormat(YYYY_MM_DD);
    List<String> dateStringList = new ArrayList<String>();
    if (endDate.before(beginDate)) {
      return dateStringList;
    }
    dateStringList.add(sdf.format(beginDate));
    Calendar cal = Calendar.getInstance();
    cal.setTime(beginDate);
    boolean flag = true;
    while (flag) {
      cal.add(Calendar.DAY_OF_MONTH, 1);
      if (endDate.after(cal.getTime())) {
        dateStringList.add(sdf.format(cal.getTime()));
      } else {
        break;
      }
    }
    if (endDate.after(beginDate)) {
      dateStringList.add(sdf.format(endDate));
    }
    return dateStringList;
  }
}
